home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / mac / macconq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  64.8 KB  |  2,728 lines  |  [TEXT/R*ch]

  1. /* Main program of the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995, 1996 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10. extern int checkpointinterval;
  11. extern int statistics_wanted;
  12. extern int numsoundplays;
  13. extern int numremotewaiting;
  14. extern void low_send(int id, char *buf);
  15. extern int low_receive(int *id, char *buf, int maxchars, int timeout);
  16. extern void update_debugging PARAMS ((void));
  17. extern void toggle_debugging PARAMS ((int *flagp));
  18. #include "macconq.h"
  19.  
  20. #include <errors.h>
  21. #include <time.h>
  22.  
  23. #ifdef __MWERKS__
  24. #include <Sound.h>
  25. #endif
  26.  
  27. #define keyReplyErr 'errn'
  28.  
  29. /* Function prototypes. */
  30.  
  31. static void handle_event(EventRecord *event);
  32.  
  33. static pascal OSErr do_ae_open_application(AppleEvent *message, AppleEvent *reply, long refcon);
  34. static pascal OSErr do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon);
  35. static pascal OSErr do_ae_print_documents(AppleEvent *message, AppleEvent *reply, long refcon);
  36. static pascal OSErr do_ae_quit_application(AppleEvent *message, AppleEvent *reply, long refcon);
  37. static pascal OSErr do_ae_join_game(AppleEvent *message, AppleEvent *reply, long refcon);
  38.  
  39. static Boolean missed_any_parameters(AppleEvent *message);
  40.  
  41. static pascal Boolean filter_warning_alert(DialogPtr dialog, EventRecord *evt, short *itemhit);
  42.  
  43. /* Global variables. */
  44.  
  45. /* This is the id of any map modal tool currently in effect. */
  46.  
  47. int map_modal = 0;
  48.  
  49. int inbackground;
  50.  
  51. /* This is the list of maps that we're using. */
  52.  
  53. struct a_map *maplist;
  54.  
  55. /* This is the list of lists. */
  56.  
  57. struct a_list *listlist;
  58.  
  59. /* This is the list of unit closeups. */
  60.  
  61. struct a_unit_closeup *unitcloseuplist;
  62.  
  63. /* This indicates whether the general game resource files was found. */
  64.  
  65. int foundresourcesfile = FALSE;
  66.  
  67. /* This flag indicates whether the image etc resource file(s) were found. */
  68.  
  69. int foundimagesfile = FALSE;
  70.  
  71. /* The usual width of a scrollbar. */
  72.  
  73. int sbarwid = 15;
  74.  
  75. /* True if new maps should show the cell grid. */
  76.  
  77. int default_draw_grid = TRUE;
  78.  
  79. /* True if new maps should display names and numbers. */
  80.  
  81. int default_draw_names = FALSE;
  82.  
  83. /* (should use these eventually instead) */
  84.  
  85. int default_draw_unit_names = FALSE;
  86. int default_draw_unit_numbers = FALSE;
  87. int default_draw_feature_names = FALSE;
  88.  
  89. /* True if we're going to use WaitNextEvent. */
  90.  
  91. int useWNE = FALSE;
  92.  
  93. /* Rectangle that constrains window dragging. */
  94.  
  95. Rect dragrect;
  96.  
  97. /* Rectangle that constrains window resizing. */
  98.  
  99. Rect sizerect;
  100.  
  101. /* This is the side that is using this Mac as its display. */
  102.  
  103. Side *dside = NULL;
  104.  
  105. /* This points to a spare block of memory that is freed so shutdown code can
  106.    use it (no guarantee that it will tho). */
  107.  
  108. Handle spare;
  109.  
  110. /* This is true if savable prefs etc have been saved since being changed. */
  111. /* (always true for now, nothing being remembered) */
  112.  
  113. int interfacestatesafe = TRUE;
  114.  
  115. /* This is true when a single click suffices to move a unit. */
  116.  
  117. int defaultmoveonclick = TRUE;
  118.  
  119. int defaultautoselect = TRUE;
  120.  
  121. int wasingame = TRUE;
  122.  
  123. int playsounds = TRUE;
  124.  
  125. /* Set to true if Color QuickDraw is installed. */
  126.  
  127. int hasColorQD;
  128.  
  129. /* The range of screen pixel depths that the display has to cope with. */
  130.  
  131. int minscreendepth = -1;
  132.  
  133. int maxscreendepth = -1;
  134.  
  135. /* This is true if AppleEvents are available. */
  136.  
  137. int hasAppleEvents;
  138.  
  139. /* This is true if the PPC toolbox is available. */
  140.  
  141. int hasPPCToolbox;
  142.  
  143. char *curdatestr = NULL;
  144.  
  145. int eventloopdone = FALSE;
  146.  
  147. int inputinvalid = FALSE;
  148.  
  149. /* True when a won or lost dialog has been put up on the screen already. */
  150.  
  151. static int told_outcome = FALSE;
  152.  
  153. MovieType movie_types[10];
  154.  
  155. struct a_movie {
  156.   enum movie_type type;
  157.   int args[5];
  158. };
  159.  
  160. /* Number of movies waiting to be played. */
  161.  
  162. int numscheduled;
  163.  
  164. /* Movies to be played. */
  165.  
  166. struct a_movie movies[10];
  167.  
  168. int connection_method;
  169.  
  170. int hosting;
  171.  
  172. ModalFilterUPP filter_warning_alert_proc;
  173.  
  174. AEEventHandlerUPP do_ae_open_application_proc;
  175. AEEventHandlerUPP do_ae_open_documents_proc;
  176. AEEventHandlerUPP do_ae_print_documents_proc;
  177. AEEventHandlerUPP do_ae_quit_application_proc;
  178. AEEventHandlerUPP do_ae_join_game_proc;
  179.  
  180. /* The main Mac program. */
  181.  
  182. int
  183. main()
  184. {
  185.     /* Do the most basic Macintosh setup. */
  186.     init_toolbox();
  187.     init_cursors();
  188.     init_patterns();
  189.     init_icons();
  190.     init_menus();
  191.     init_rects();
  192.     /* Put the Xconq kernel into a known state. */
  193.     clear_game_modules();
  194.     init_data_structures();
  195.     init_library_path(NULL);
  196.     init_ae();
  197.     /* Acquire Mac-specific files (preferences and resources). */
  198.     get_files();
  199.     /* A hack to ensure some memory available for error handling. */
  200.     spare = NewHandle(2000);
  201.     /* If no Apple Events, go to the splash screen now, otherwise we'll wait
  202.        for an oapp/odoc/pdoc event to decide what to do. */
  203.     if (!hasAppleEvents) {
  204.         if (splash_dialog() == diSplashQuit)
  205.           return 0;
  206.     }
  207.     /* All essential init done, jump into the main event loop. */
  208.     event_loop();
  209.     /* Will exit here, or perhaps via error. */
  210.     return 0;
  211. }
  212.  
  213. /* This is the first dialog that the user sees.  It doesn't do much
  214.    besides provide the initial choice into the program proper. */
  215.  
  216. int
  217. splash_dialog()
  218. {
  219.     switch (do_splash_box()) {
  220.         case diSplashNew:
  221.             new_game_dialog();
  222.             break;
  223.         case diSplashOpen:
  224.             open_game_dialog();
  225.             break;
  226.         case diSplashConnect:
  227.             hosting = FALSE;
  228.             connect_game_dialog();
  229.             break;
  230.         case diSplashQuit:
  231.             return diSplashQuit;
  232.     }
  233.     return -1;
  234. }
  235.  
  236. /* Do the usual Mac setup calls. */
  237.  
  238. void
  239. init_toolbox()
  240. {
  241.     SysEnvRec se;
  242.  
  243.     MaxApplZone();
  244.  
  245.     InitGraf(&QD(thePort));
  246.     InitFonts();
  247.     FlushEvents(everyEvent, 0);
  248.     InitWindows();
  249.     InitMenus();
  250.     TEInit();
  251.     InitDialogs(NULL);
  252.     InitCursor();
  253.  
  254.     /* We need to set this one up early, since may be used in error
  255.        reporting. */
  256.     filter_warning_alert_proc = NewModalFilterProc(filter_warning_alert);
  257.  
  258.     SysEnvirons(2, &se);
  259.     hasColorQD = se.hasColorQD;
  260.     DGprintf("%s Color QuickDraw\n", (hasColorQD ? "Using" : "Not using"));
  261.     recalc_depths();
  262. }
  263.  
  264. /* Look at all the devices and compute the range of screen depths. */
  265.  
  266. void
  267. recalc_depths()
  268. {
  269.     int depth, oldmin = minscreendepth, oldmax = maxscreendepth;
  270.     GDHandle gdev;
  271.  
  272.     if (hasColorQD) {
  273.         gdev = GetDeviceList();
  274.         minscreendepth = maxscreendepth = (*((*gdev)->gdPMap))->pixelSize;
  275.         while ((gdev = GetNextDevice(gdev)) != nil) {
  276.             depth = (*((*gdev)->gdPMap))->pixelSize;
  277.             if (depth < minscreendepth)
  278.               minscreendepth = depth;
  279.             if (depth > maxscreendepth)
  280.               maxscreendepth = depth;
  281.         }
  282.     } else {
  283.         minscreendepth = maxscreendepth = 1;
  284.     }
  285.     if (minscreendepth != oldmin || maxscreendepth != oldmax) {
  286.         DGprintf("Screen depths range from %d to %d\n", minscreendepth, maxscreendepth);
  287.     }
  288. }
  289.  
  290. /* Set up the generic dragging and sizing rects. */
  291.  
  292. void
  293. init_rects()
  294. {
  295.     RgnHandle screenrgn;
  296.  
  297.     screenrgn = GetGrayRgn();
  298.     dragrect = (*screenrgn)->rgnBBox;
  299.     SetRect(&sizerect, 50, 50, (*screenrgn)->rgnBBox.right,  (*screenrgn)->rgnBBox.bottom);
  300. }
  301.  
  302. /* Basic Apple Event handling. */
  303.  
  304. void
  305. init_ae()
  306. {
  307.     OSErr err;
  308.     long rslt;
  309.  
  310.     hasPPCToolbox  = (Gestalt(gestaltPPCToolboxAttr, &rslt) ? false : (rslt != 0));
  311.     hasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &rslt) ? false : (rslt != 0));
  312.  
  313.     if (hasAppleEvents) {
  314.         do_ae_open_application_proc = NewAEEventHandlerProc(do_ae_open_application);
  315.         do_ae_open_documents_proc = NewAEEventHandlerProc(do_ae_open_documents);
  316.         do_ae_print_documents_proc = NewAEEventHandlerProc(do_ae_print_documents);
  317.         do_ae_quit_application_proc = NewAEEventHandlerProc(do_ae_quit_application);
  318.         do_ae_join_game_proc = NewAEEventHandlerProc(do_ae_join_game);
  319.  
  320.         err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
  321.                                     do_ae_open_application_proc, 0L, false);
  322.         if (err) {
  323.             init_warning("AppleEvent handler could not be installed, skipping others");
  324.             return;
  325.         }
  326.         err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
  327.                                     do_ae_open_documents_proc, 0L, false);
  328.         if (err) {
  329.             init_warning("AppleEvent handler could not be installed, skipping others");
  330.             return;
  331.         }
  332.         err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
  333.                                     do_ae_print_documents_proc, 0L, false);
  334.         if (err) {
  335.             init_warning("AppleEvent handler could not be installed, skipping others");
  336.             return;
  337.         }
  338.         err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  339.                                     do_ae_quit_application_proc, 0L, false);
  340.         if (err) {
  341.             init_warning("AppleEvent handler could not be installed, skipping others");
  342.             return;
  343.         }
  344.         err = AEInstallEventHandler('xcnq', 'join',
  345.                                     do_ae_join_game_proc, 0L, false);
  346.         if (err) {
  347.             init_warning("AppleEvent handler could not be installed, skipping others");
  348.             return;
  349.         }
  350.     }
  351. }
  352.  
  353. short prefs_refnum = -1;
  354.  
  355. /* Open and/or load any files that we might need, such as preferences
  356.    and resources. */
  357.  
  358. void
  359. get_files()
  360. {
  361.     Str255 filename;
  362.     extern short initialvrefnum;
  363.  
  364.     /* Capture the current vrefnum. */
  365.     GetVol(NULL, &initialvrefnum);
  366.     /* Load up any preferences. */
  367.     /* As a concession to Mac-ness, we disable statistics writing by default, and require
  368.        a preference that it be on.  This can be removed when the user gets to choose the
  369.        name of the statistics file before it is written. */
  370.     statistics_wanted = FALSE;
  371.     get_preferences();
  372.     /* Look for and open game library resource files. */
  373.     foundresourcesfile = FALSE;
  374.     GetIndString(filename, sFilenames, siResources);
  375.     if (OpenResFile(filename) != -1) {
  376.         foundresourcesfile = TRUE;
  377.     }
  378.     foundimagesfile = FALSE;
  379.     GetIndString(filename, sFilenames, siImages);
  380.     if (OpenResFile(filename) != -1) {
  381.         foundimagesfile = TRUE;
  382.     }
  383.     GetIndString(filename, sFilenames, siSounds);
  384.     if (OpenResFile(filename) != -1) {
  385.         /* (need to do anything special if sounds not found??) */
  386.     }
  387.     /* Note that we don't complain yet if the resource/image files are missing,
  388.        since we don't yet know whether we actually need anything from them.
  389.        (Images etc might be built into app or game module, for instance.) */
  390. }
  391.  
  392. int
  393. open_preferences()
  394. {
  395.     short vref;
  396.     long dirid;
  397.     OSErr err;
  398.     Str255 filename;
  399.  
  400.     GetIndString(filename, sFilenames, siPreferences);
  401.     /* (should do a gestalt check first) */
  402.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
  403.                    &vref, &dirid);
  404.     if (err != noErr) {
  405.         SysEnvRec se;
  406.  
  407.         err = SysEnvirons(1, &se);
  408.         if (err == noErr) {
  409.             vref = se.sysVRefNum;
  410.         } else {
  411.             vref = 0;
  412.         }
  413.         dirid = 0;
  414.     }
  415.     err = HCreate(vref, dirid, filename, XconqSignature, 'pref');
  416.     if (err == dupFNErr)
  417.       err = noErr;
  418.     if (err == noErr) {
  419.         /* Ensure that the resource fork exists. */
  420.         HCreateResFile(vref, dirid, filename);
  421.         prefs_refnum = HOpenResFile(vref, dirid, filename, fsRdWrPerm);
  422.         if (prefs_refnum == -1)
  423.             err = -1;
  424.         if (ResError())
  425.             err = ResError();
  426.     }
  427.     return err;
  428. }
  429.  
  430. void
  431. close_preferences()
  432. {
  433.     CloseResFile(prefs_refnum);
  434.     prefs_refnum = -1;
  435. }
  436.  
  437. void
  438. get_preferences()
  439. {
  440.     int startlineno = 0, endlineno = 0;
  441.     Obj *uispec;
  442.     OSErr err;
  443.     Handle prefs;
  444.  
  445.     err = open_preferences();
  446.     if (err == noErr) {
  447.         UseResFile(prefs_refnum);
  448.         prefs = GetResource('XCpf', 128);
  449.         if (prefs != nil) {
  450.             uispec = read_form_from_string(copy_string(*prefs), &startlineno, &endlineno);
  451.             interp_mac_ui_data(uispec);
  452.         }
  453.         close_preferences();
  454.     }
  455. }
  456.  
  457. void
  458. save_preferences()
  459. {
  460.     int cur_refnum;
  461.     char prefbuf[300];
  462.     OSErr err;
  463.     Handle oldprefs, prefs;
  464.  
  465.     err = open_preferences();
  466.     if (err == noErr) {
  467.         ui_save_state(dside);
  468.         sprintlisp(prefbuf, find_at_key(dside->uidata, "mac"));
  469.         /* Copy the string into a handle that will be used for the resource. */
  470.         prefs = NewHandle(strlen(prefbuf) + 1);
  471.         HLock(prefs);
  472.         strcpy(*prefs, prefbuf);
  473.         HUnlock(prefs);
  474.         cur_refnum = CurResFile();
  475.         UseResFile(prefs_refnum);
  476.         oldprefs = GetResource('XCpf', 128);
  477.         if (oldprefs != nil) {
  478.             RmveResource(oldprefs);
  479.             UpdateResFile(prefs_refnum);
  480.         }
  481.         AddResource(prefs, 'XCpf', 128, "\pXconq Preferences");
  482.         close_preferences();
  483.         UseResFile(cur_refnum);
  484.     }
  485. }
  486.  
  487. void
  488. interp_mac_ui_data(Obj *uispec)
  489. {
  490.     int numval;
  491.     char *name;
  492.     Obj *rest, *bdg;
  493.  
  494.     for (rest = uispec; rest != lispnil; rest = cdr(rest)) {
  495.         bdg = car(rest);
  496.         if (!consp(bdg)) {
  497.             /* Don't complain out loud normally, confusing to users
  498.                because preferences are under Xconq and not user control. */
  499.             Dprintf("Syntax error in preference binding?\n");
  500.             continue;
  501.         }
  502.         if (symbolp(car(bdg))) {
  503.             name = c_string(car(bdg));
  504.             numval = 0;
  505.             if (numberp(cadr(bdg))) {
  506.                 numval = c_number(cadr(bdg));
  507.             } else {
  508.                 Dprintf("Preference property `%s' has non-numeric value, setting to zero\n",
  509.                         name);
  510.             }
  511.             if (strcmp(name, "sound") == 0) {
  512.                 playsounds = numval;
  513.             } else if (strcmp(name, "default-draw-grid") == 0) {
  514.                 default_draw_grid = numval;
  515.             } else if (strcmp(name, "default-draw-names") == 0) {
  516.                 default_draw_names = numval;
  517.             } else if (strcmp(name, "checkpoint-interval") == 0) {
  518.                 checkpointinterval = numval;
  519.             } else if (strcmp(name, "want-statistics") == 0) {
  520.                 statistics_wanted = numval;
  521.             } else {
  522.                 /* Ignore unrecognized properties. */
  523.                 Dprintf("Preference binding `%s' unrecognized\n", name);
  524.             }
  525.         } else {
  526.             /* As with above comment. */
  527.             Dprintf("Syntax error in preference binding head?\n");
  528.         }
  529.     }
  530. }
  531.  
  532. void
  533. ui_save_state(Side *side)
  534. {
  535.     /* We don't do anything here because the ui data is kept up-to-date. */
  536. }
  537.  
  538. void
  539. ui_update_state()
  540. {
  541.     Obj *state = lispnil;
  542.  
  543.     push_binding(&state, intern_symbol("want-statistics"), new_number(statistics_wanted));
  544.     push_binding(&state, intern_symbol("checkpoint-interval"), new_number(checkpointinterval));
  545.     push_binding(&state, intern_symbol("default-draw-grid"), new_number(default_draw_grid));
  546.     push_binding(&state, intern_symbol("default-draw-names"), new_number(default_draw_names));
  547.     push_binding(&state, intern_symbol("sound"), new_number(playsounds));
  548.     dside->uidata = replace_at_key(dside->uidata, "mac", state);
  549. }
  550.  
  551. /* Dialogue to set the preferences. */
  552.  
  553. void
  554. set_preferences()
  555. {
  556.     short done = FALSE, ditem;
  557.     DialogPtr win;
  558.     short itemtype;  Handle itemhandle;  Rect itemrect;
  559.  
  560.     win = GetNewDialog(dPreferences, NULL, (DialogPtr) -1L);
  561.     /* Set the current preferences into the items. */
  562.     GetDItem(win, diPrefsGrid, &itemtype, &itemhandle, &itemrect);
  563.     SetCtlValue((ControlHandle) itemhandle, default_draw_grid);
  564.     GetDItem(win, diPrefsNames, &itemtype, &itemhandle, &itemrect);
  565.     SetCtlValue((ControlHandle) itemhandle, default_draw_names);
  566.     GetDItem(win, diPrefsCheckpoint, &itemtype, &itemhandle, &itemrect);
  567.     SetCtlValue((ControlHandle) itemhandle, (checkpointinterval > 0));
  568.     GetDItem(win, diPrefsStatistics, &itemtype, &itemhandle, &itemrect);
  569.     SetCtlValue((ControlHandle) itemhandle, statistics_wanted);
  570.     ShowWindow(win);
  571.     while (!done) {
  572.         SetCursor(&QD(arrow));
  573.         ModalDialog(NULL, &ditem);
  574.         switch (ditem) {
  575.             case diPrefsOK:
  576.                 /* Actually change the program's variables. */
  577.                 GetDItem(win, diPrefsGrid, &itemtype, &itemhandle, &itemrect);
  578.                 default_draw_grid = GetCtlValue((ControlHandle) itemhandle);
  579.                 GetDItem(win, diPrefsNames, &itemtype, &itemhandle, &itemrect);
  580.                 default_draw_names = GetCtlValue((ControlHandle) itemhandle);
  581.                 GetDItem(win, diPrefsCheckpoint, &itemtype, &itemhandle, &itemrect);
  582.                 checkpointinterval = (GetCtlValue((ControlHandle) itemhandle) ? 5 : 0);
  583.                 GetDItem(win, diPrefsStatistics, &itemtype, &itemhandle, &itemrect);
  584.                 statistics_wanted = GetCtlValue((ControlHandle) itemhandle);
  585.                 /* Remember all these settings. */
  586.                 ui_update_state();
  587.                 save_preferences();
  588.                 /* Fall into next case. */
  589.             case diPrefsCancel:
  590.                 done = TRUE;
  591.                 break;
  592.             case diPrefsGrid:
  593.             case diPrefsNames:
  594.             case diPrefsStatistics:
  595.                 /* Toggle check boxes. */
  596.                 GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
  597.                 SetCtlValue((ControlHandle) itemhandle, !GetCtlValue((ControlHandle) itemhandle));
  598.                 break;
  599.             case diPrefsCheckpoint:
  600.                 GetDItem(win, ditem, &itemtype, &itemhandle, &itemrect);
  601.                 SetCtlValue((ControlHandle) itemhandle, !GetCtlValue((ControlHandle) itemhandle));
  602.                 /* Should enable/disable interval-setting ditems. */
  603.                 break;
  604.             case diPrefsInterval:
  605.                 break;
  606.         }
  607.     }
  608.     DisposDialog(win);
  609. }
  610.  
  611. /* Since Mac programs effectively take over the entire machine, we depend on
  612.    this event loop to handle everything that might come along.  */
  613.  
  614. void
  615. event_loop()
  616. {
  617.     int done = FALSE;
  618.     Boolean gotevent;
  619.     Point mouse;
  620.     EventRecord    event;
  621.     RgnHandle cursorRgn;
  622.     short itemhit;
  623.     DialogPtr dialog;
  624.  
  625.     /* Figure out if the WaitNextEvent Trap is available. */
  626.     useWNE = (NGetTrapAddress(0x60, ToolTrap) != NGetTrapAddress(0x9f, ToolTrap));
  627.     /* Pass WNE an empty region the 1st time thru. */
  628.     cursorRgn = NewRgn();
  629.     /* Loop (almost) forever. */
  630.     while (!eventloopdone) {
  631.         /* Use WaitNextEvent if it is available, otherwise GetNextEvent. */
  632.         if (useWNE) {
  633.             get_global_mouse(&mouse);
  634.             adjust_cursor(mouse, cursorRgn);
  635.             gotevent = WaitNextEvent(everyEvent, &event, 0L, cursorRgn);
  636.         } else {
  637.             SystemTask();
  638.             gotevent = GetNextEvent(everyEvent, &event);
  639.         }
  640.         /* First decide if the event is for a dialog or is just any old event. */
  641.         if (FrontWindow() != nil && IsDialogEvent(&event)) {
  642.             /* Handle all the modeless dialogs here. */
  643.             /* Process any player setup window events that we want to handle
  644.                specially (such as keystrokes). */
  645.             if (playersetupwin != nil && playersetupwin == FrontWindow())
  646.               handle_player_setup_event(&event);
  647.             if (DialogSelect(&event, &dialog, &itemhit)) {
  648.                 if (dialog == instructionswin) {
  649.                     hit_instructions_dialog(dialog, itemhit, &event);
  650.                 }
  651.                 /* Process player setup window events that the Dialog
  652.                    Manager handles (clicks on buttons for instance). */
  653.                 if (dialog == playersetupwin) {
  654.                     mouse = event.where;
  655.                     SetPort(playersetupwin);
  656.                     GlobalToLocal(&mouse);
  657.                     if (hit_player_setup_dialog(itemhit, mouse))
  658.                       launch_game_2();
  659.                 }
  660.                 /* If this was something like a key or click event, but wasn't handled
  661.                    by the dialog, we're done and can go wait for the next event.
  662.                    Otherwise, for null events, fall through to the usual handling. */
  663.                 if (gotevent)
  664.                   continue;
  665.             }
  666.         }
  667.         if (gotevent) {
  668.             /* Make sure we have the right cursor before handling the event. */
  669.             adjust_cursor(event.where, cursorRgn);
  670.             handle_event(&event);
  671.         } else if (beforestart && hosting && connection_method > 0 && numremotewaiting > 0) {
  672.             int gotsome, remoteid;
  673.  
  674.             gotsome = low_receive(&remoteid, NULL, 0, 0);
  675.             if (gotsome) {
  676.                 add_remote_player(NULL);
  677.             }
  678.         } else if (!beforestart && !endofgame) {
  679.             /* On null events, give the kernel a chance to run something. */
  680.             /* DON'T automatically go to a watch cursor, since run_game often
  681.                returns very quickly.  Instead, long-running subroutines should
  682.                call back to put a watch cursor up. */
  683.             run_game(1);
  684.             maybe_select_next_unit();
  685.             /* If the game ended, force various changes in interaction. */
  686.             if (endofgame)
  687.               set_end_of_game_interaction_modes();
  688.         }
  689.         /* Blink TE cursors regularly. */
  690.         if (commandwin != nil && FrontWindow() == commandwin) {
  691.             TEIdle(command_text);
  692.         }
  693.     }
  694. }
  695.  
  696. void
  697. get_global_mouse(Point *mouse)
  698. {
  699.     EventRecord    evt;
  700.     
  701.     OSEventAvail(0, &evt);
  702.     *mouse = evt.where;
  703. }
  704.  
  705. void
  706. set_end_of_game_interaction_modes()
  707. {
  708.     Map *map;
  709.  
  710.     for_all_maps(map) {
  711.         map->moveonclick = map->autoselect = FALSE;
  712.         force_update(map->window);
  713.     }
  714. }
  715.  
  716. Point lastmouse;
  717.  
  718. char mouseoverbuf[100];
  719.  
  720. /* Change the cursor to reflect the context. */
  721.  
  722. void
  723. adjust_cursor(Point mouse, RgnHandle region)
  724. {
  725.     int x, y, approxdir = 1, usual = TRUE;
  726.     Unit *unit = NULL;
  727.     extern char *mouseover;
  728.     Map *map;
  729.     CursPtr adjust_designer_cursor();
  730.     GrafPtr oldport;
  731.  
  732.     map = map_from_window(FrontWindow());
  733.     if (map != NULL) {
  734.         GetPort(&oldport);
  735.         SetPort(map->window);
  736.         GlobalToLocal(&mouse);
  737.         if (mouse.h > conwid && mouse.h < map->window->portRect.right - sbarwid
  738.             && mouse.v > map->toph && mouse.v < map->window->portRect.bottom - sbarwid) {
  739.             if (map_modal != NO_MODAL) {
  740.                 switch (map_modal) {
  741.                     case FIRE_MODAL:
  742.                     case FIRE_INTO_MODAL:
  743.                         SetCursor(*firecursor);
  744.                         break;
  745.                     case MOVE_TO_MODAL:
  746.                     case SET_FORMATION_MODAL:
  747.                     case ADD_TERRAIN_MODAL:
  748.                     case REMOVE_TERRAIN_MODAL:
  749.                     case DISTANCE_MODAL:
  750.                     case ZOOM_MODAL:
  751.                     case GENERIC_MODAL:
  752.                         SetCursor(*opencrosscursor);
  753.                         break;
  754.                     default:
  755.                         run_error("unknown modal tool %d", map_modal);
  756.                         break;
  757.                 }
  758.                 usual = FALSE;
  759. #ifdef DESIGNERS
  760.             } else if (dside->designer && tooltype != notool) {
  761.                 SetCursor(adjust_designer_cursor(mouse, region));  usual = FALSE;
  762. #endif DESIGNERS
  763.             } else if (map->moveonclick) {
  764.                 if (map->numselections == 1
  765.                     && (unit = map->selections[0]) != NULL) {
  766.                     /* Calculate the approx dir to here from selected unit. */
  767.                     m_nearest_cell(map, mouse.h, mouse.v, &x, &y);
  768.                     /* Note that we allow x,y here to be outside the world. */
  769.                     if (mobile(unit->type)
  770.                         && (approxdir = approx_dir(x - unit->x, y - unit->y)) >= 0) {
  771.                         SetCursor(*(movecursors[approxdir]));  usual = FALSE;
  772.                     } else {
  773.                         SetCursor(*nomovecursor);  usual = FALSE;
  774.                     }
  775.                 } else if (map->numselections > 1) {
  776.                     SetCursor(*allmovecursor);  usual = FALSE;
  777.                 } else {
  778.                     /* (this is a little confusing here if no units are selected, since
  779.                        will just be arrow cursor) */
  780.                 }
  781.             }
  782.             /* This isn't really "cursor adjustment", but this is the right place
  783.                to do it - change the topline of the map to indicate what the cursor
  784.                is over. */
  785.             if (map->toplineh > 0 && !EqualPt(mouse, lastmouse)) {
  786.                 oneliner(map, mouse.h, mouse.v);
  787.                 if (strcmp(tmpbuf, mouseoverbuf) != 0) {
  788.                     strcpy(mouseoverbuf, tmpbuf);
  789.                     mouseover = mouseoverbuf;
  790.                     draw_top_line(map);
  791.                 }
  792.                 lastmouse = mouse;
  793.             }
  794.         } else {
  795.             if (map->toplineh > 0) {
  796.                 if (mouseover != NULL) {
  797.                     mouseover = NULL;
  798.                     draw_top_line(map);
  799.                 }
  800.             }
  801.         }
  802.         SetPort(oldport);
  803.     }
  804.     
  805.     if (endofgame || (!beforestart && dside && !dside->ingame)) {
  806.         SetCursor(*grayarrowcursor);
  807.         return;
  808.     }
  809.     /* If we got here and no cursor has been set already, go with the basic arrow. */
  810.     if (usual)
  811.       SetCursor(&QD(arrow));
  812. }
  813.  
  814. /* Decipher an event. */
  815.  
  816. void
  817. handle_event(EventRecord *event)
  818. {
  819.     short part, err;
  820.     WindowPtr win;
  821.     char key;
  822.     Point pnt;
  823.  
  824.     switch (event->what) {
  825.         case mouseDown:
  826.             /* See if the click happened in a special part of the screen. */
  827.             part = FindWindow(event->where, &win);
  828.             switch (part) {
  829.                 case inMenuBar:
  830.                     adjust_menus();
  831.                     do_menu_command(MenuSelect(event->where));
  832.                     break;
  833.                 case inSysWindow:
  834.                     SystemClick(event, win);
  835.                     break;
  836.                 case inContent:
  837.                     if (win != FrontWindow()) {
  838.                         /* Bring the clicked-on window to the front. */
  839.                         SelectWindow(win);
  840.                         /* Fix the menu to match the new front window. */
  841.                         adjust_menus();
  842.                         /* We always want to discard the event now, since clicks in a
  843.                            windows are often irreversible actions. */
  844.                     } else {
  845.                         /* Mouse clicks in the front window do something useful. */
  846.                         do_mouse_down(win, event);
  847.                     }
  848.                     break;
  849.                 case inDrag:
  850.                     /* Standard drag behavior, no tricks necessary. */
  851.                     DragWindow(win, event->where, &dragrect);
  852.                     break;
  853.                 case inGrow:
  854.                     grow_window(win, event->where);
  855.                     break;
  856.                 case inZoomIn:
  857.                 case inZoomOut:
  858.                     zoom_window(win, event->where, part);
  859.                     break;
  860.                 case inGoAway:
  861.                     if (TrackGoAway(win, event->where))
  862.                       close_window(win);
  863.                     break;
  864.             }
  865.             break;
  866.         case keyDown:
  867.         case autoKey:
  868.             key = event->message & charCodeMask;
  869.             /* Check for menukey equivalents. */
  870.             if (event->modifiers & cmdKey) {
  871.                 if (event->what == keyDown) {
  872.                     adjust_menus();
  873.                     do_menu_command(MenuKey(key));
  874.                 }
  875.             } else {
  876.                 if (event->what == keyDown) {
  877.                     int handled = FALSE;
  878.  
  879.                     /* Random keypress, interpret it. */
  880.                     if (FrontWindow() == constructionwin)
  881.                       handled = do_key_down_construction(key);
  882.                     if (FrontWindow() == commandwin)
  883.                       handled = do_key_down_command(key);
  884.                     if (!handled)
  885.                       do_keyboard_command(key);
  886.                 }
  887.             }
  888.             break;
  889.         case activateEvt:
  890.             activate_window((WindowPtr) event->message, event->modifiers & activeFlag);
  891.             break;
  892.         case updateEvt:
  893.             update_window((WindowPtr) event->message);
  894.             break;
  895.         case diskEvt:
  896.             /*    Call DIBadMount in response to a diskEvt, so that the user can format
  897.                  a floppy. (from DTS Sample) */
  898.             if (HiWord(event->message) != noErr) {
  899.                 SetPt(&pnt, 50, 50);
  900.                 err = DIBadMount(pnt, event->message);
  901.             }
  902.             break;
  903.         case app4Evt:
  904.             /* Grab only a single byte. */
  905.             switch ((event->message >> 24) & 0xFF) {
  906.                 case 0xfa:
  907.                     break;
  908.                 case 1:
  909.                     inbackground = !(event->message & 1);
  910.                     activate_window(FrontWindow(), !inbackground);
  911.                     break;
  912.             }
  913.             break;
  914.         case kHighLevelEvent:
  915.             AEProcessAppleEvent(event);
  916.             break;
  917. #if 0 /* null events don't come through here */
  918.         case nullEvent:
  919.             break;
  920. #endif
  921.             break;
  922.         default:
  923.             break;
  924.     }
  925. #ifdef DEBUGGING
  926.     /* This just forces output into the file. */
  927.     update_debugging();
  928. #endif
  929. }
  930.  
  931. /* Handle window growing by mindlessly tracking via GrowWindow,
  932.    then passing the chosen size to specific window resize handlers
  933.    or else doing the generic resize. */
  934.  
  935. void
  936. grow_window(WindowPtr win, Point where)
  937. {
  938.     long winsize;
  939.     short winh, winv;
  940.     GrafPtr oldport;
  941.  
  942.     if ((winsize = GrowWindow(win, where, &sizerect)) != 0) {
  943.         GetPort(&oldport);
  944.         SetPort(win);
  945.         winh = LoWord(winsize);  winv = HiWord(winsize);
  946.         if (map_from_window(win)) {
  947.             grow_map(map_from_window(win), winh, winv);
  948.         } else if (list_from_window(win)) {
  949.             grow_list(list_from_window(win), winh, winv);
  950.         } else if (win == historywin) {
  951.             grow_history(winh, winv);
  952.         } else if (win == constructionwin) {
  953.             grow_construction(winh, winv);
  954.         } else if (win == helpwin) {
  955.             grow_help(winh, winv);
  956.         } else if (win == noticewin) {
  957.             grow_notice(winh, winv);
  958.         } else if (win == scoreswin) {
  959.             grow_scores(winh, winv);
  960.         }
  961.         SetPort(oldport);
  962.     }
  963. }
  964.  
  965. void
  966. zoom_window(WindowPtr win, Point where, int part)
  967. {
  968.     GrafPtr oldport;
  969.  
  970.     if (TrackBox(win, where, part)) {
  971.         GetPort(&oldport);
  972.         /* The window must be the current port. (ZoomWindow bug) */
  973.         SetPort(win);
  974.         if (map_from_window(win)) {
  975.             zoom_map(map_from_window(win), part);
  976.         } else if (list_from_window(win)) {
  977.             zoom_list(list_from_window(win), part);
  978.         } else if (win == constructionwin) {
  979.             zoom_construction(part);
  980.         } else if (win == historywin) {
  981.             zoom_history(part);
  982.         } else if (win == helpwin) {
  983.             zoom_help(part);
  984.         } else if (win == noticewin) {
  985.             zoom_notice(part);
  986.         } else if (win == scoreswin) {
  987.             zoom_scores(part);
  988.         } else {
  989.             /* Generic window zooming. */
  990.             EraseRect(&win->portRect);
  991.             ZoomWindow(win, part, true);
  992.             InvalRect(&win->portRect);
  993.         }
  994.         SetPort(oldport);
  995.     }
  996. }
  997.  
  998. void
  999. close_window(WindowPtr win)
  1000. {
  1001.     if (is_da_window(win)) {
  1002.         CloseDeskAcc(((WindowPeek) win)->windowKind);
  1003.     } else if (is_app_window(win)) {
  1004.         /* Remove from the windows menu (OK to call even if window not in menu). */
  1005.         remove_window_menu_item(win);
  1006.         /* Do special activities for some window subtypes. */
  1007.         if (map_from_window(win)) {
  1008.             destroy_map(map_from_window(win));
  1009.         } else if (list_from_window(win)) {
  1010.             destroy_list(list_from_window(win));
  1011.         } else if (unit_closeup_from_window(win)) {
  1012.             destroy_unit_closeup(unit_closeup_from_window(win));
  1013. #ifdef DESIGNERS
  1014.         } else if (win == designwin) {
  1015.             /* Closing the design palette implies we're done designing. */
  1016.             disable_designing();
  1017. #endif /* DESIGNERS */
  1018.         }
  1019.         /* Remove the window from our sight, will provoke update events. */
  1020.         HideWindow(win);
  1021.         /* At least for now, don't actually dispose of the window. */
  1022.     }
  1023. }
  1024.  
  1025. /* This just dispatches to the appropriate window handler. */
  1026.  
  1027. void
  1028. do_mouse_down(WindowPtr window, EventRecord *event)
  1029. {
  1030.     Point mouse;
  1031.     Map *map;
  1032.     List *list;
  1033.     UnitCloseup *unitcloseup;
  1034.  
  1035.     if (is_app_window(window)) {
  1036.         SetPort(window);
  1037.         mouse = event->where;
  1038.         GlobalToLocal(&mouse);
  1039.         /* Locate the interface object that this is on. */
  1040.         if ((map = map_from_window(window)) != NULL) {
  1041.             do_mouse_down_map(map, mouse, event->modifiers); 
  1042.         } else if ((list = list_from_window(window)) != NULL) {
  1043.             do_mouse_down_list(list, mouse, event->modifiers); 
  1044.         } else if ((unitcloseup = unit_closeup_from_window(window)) != NULL) {
  1045.             do_mouse_down_unit_closeup(unitcloseup, mouse, event->modifiers); 
  1046.         } else if (window == gamewin) {
  1047.             do_mouse_down_game(mouse, event->modifiers);
  1048.         } else if (window == historywin) {
  1049.             do_mouse_down_history(mouse, event->modifiers);
  1050.         } else if (window == constructionwin) {
  1051.             do_mouse_down_construction(mouse, event->modifiers);
  1052.         } else if (window == helpwin) {
  1053.             do_mouse_down_help(mouse, event->modifiers);
  1054.         } else if (window == noticewin) {
  1055.             do_mouse_down_notice(mouse, event->modifiers);
  1056.         } else if (window == commandwin) {
  1057.             do_mouse_down_command(mouse, event->modifiers);
  1058.         } else if (window == scoreswin) {
  1059.             do_mouse_down_scores(mouse, event->modifiers);
  1060. #ifdef DESIGNERS
  1061.         } else if (window == designwin) {
  1062.             do_mouse_down_design(mouse, event->modifiers);
  1063. #endif /* DESIGNERS */
  1064.         }
  1065.     } else {
  1066.         /* ??? */
  1067.     }
  1068. }
  1069.  
  1070. /* Bringing a window to the front may entail messing with the menu. */
  1071.  
  1072. void
  1073. activate_window(WindowPtr win, int activate)
  1074. {
  1075.     Map *map;
  1076.     List *list;
  1077.  
  1078.     if (win == nil)
  1079.       return;
  1080.     if (activate) {
  1081.         /* It's convenient to make the activated window also be the current GrafPort. */
  1082.         SetPort(win);
  1083.     }
  1084.     adjust_menus();
  1085.     if ((map = map_from_window(win)) != NULL) {
  1086.         activate_map(map, activate);
  1087.     } else if ((list = list_from_window(win)) != NULL) {
  1088.         activate_list(list, activate);
  1089.     } else if (win == constructionwin) {
  1090.         activate_construction(activate);
  1091.     } else if (win == helpwin) {
  1092.         activate_help(activate);
  1093.     } else if (win == noticewin) {
  1094.         activate_notice(activate);
  1095.     } else if (win == commandwin) {
  1096.         activate_command(activate);
  1097.     } else if (win == scoreswin) {
  1098.         activate_scores(activate);
  1099.     } else {
  1100.         DGprintf("%sactivating random window\n", (activate ? "" : "de"));
  1101.     }
  1102. }
  1103.  
  1104. /* Update a given window.  This is the main routine that causes drawing into
  1105.    all the different kinds of windows. */
  1106.  
  1107. void
  1108. update_window(WindowPtr win)
  1109. {
  1110.     int controls = TRUE, growbox = FALSE;
  1111.     GrafPtr oldport;
  1112.     Map *map;
  1113.     List *list;
  1114.     UnitCloseup *unitcloseup;
  1115.  
  1116.     /* Set the updating window to be the current grafport. */
  1117.     GetPort(&oldport);
  1118.     SetPort(win);
  1119.     recalc_depths();
  1120.     BeginUpdate(win);
  1121.     if ((map = map_from_window(win)) != NULL) {
  1122.         draw_map(map);
  1123.         growbox = TRUE;
  1124.     } else if ((list = list_from_window(win)) != NULL) {
  1125.         draw_list(list);
  1126.         growbox = TRUE;
  1127.     } else if ((unitcloseup = unit_closeup_from_window(win)) != NULL) {
  1128.         draw_unit_closeup(unitcloseup);
  1129.     } else if (win == gamewin) {
  1130.         draw_game();
  1131.         controls = FALSE;
  1132.     } else if (win == historywin) {
  1133.         draw_history();
  1134.         growbox = TRUE;
  1135.     } else if (win == constructionwin) {
  1136.         draw_construction();
  1137.         growbox = TRUE;
  1138.     } else if (win == helpwin) {
  1139.         draw_help();
  1140.         growbox = TRUE;
  1141.     } else if (win == noticewin) {
  1142.         draw_notice();
  1143.         growbox = TRUE;
  1144.     } else if (win == commandwin) {
  1145.         draw_command();
  1146.         growbox = FALSE;
  1147.     } else if (win == scoreswin) {
  1148.         draw_scores();
  1149.         growbox = TRUE;
  1150. #ifdef DESIGNERS
  1151.     } else if (win == designwin) {
  1152.         draw_design_window();
  1153.         controls = FALSE;
  1154. #endif /* DESIGNERS */
  1155.     } else {
  1156.         controls = FALSE;
  1157.     }
  1158.     if (controls) {
  1159.         UpdateControls(win, win->visRgn);
  1160.     }
  1161.     if (growbox) {
  1162.         DrawGrowIcon(win);
  1163.     }
  1164.     EndUpdate(win);
  1165.     SetPort(oldport);
  1166. }
  1167.  
  1168. static int last_tick_count = 0;
  1169.  
  1170. void
  1171. maybe_select_next_unit()
  1172. {
  1173.     Unit *unit;
  1174.     Map *map;
  1175.  
  1176.     if ((!beforestart && !endofgame)
  1177.         && (map = map_from_window(FrontWindow())) != NULL
  1178.         && map->autoselect) {
  1179.         /* Hunt around for a reasonable "next unit" to select. */
  1180.         /* Scroll over to the current unit if appropriate. */
  1181.         if (map->curunit != NULL
  1182.             && in_play(map->curunit)
  1183.             && (map->curunit->act
  1184.                 && map->curunit->act->acp > 0)  /* should be "above min"? */
  1185.             && (map->curunit->plan
  1186.                 && !map->curunit->plan->asleep
  1187.                 && !map->curunit->plan->reserve
  1188.                 && !map->curunit->plan->delayed)
  1189.             && map->scrolltocurunit
  1190.             ) {
  1191.             scroll_to_unit(map, map->curunit);
  1192.             map->scrolltocurunit = FALSE;
  1193.             goto blink;
  1194.         }
  1195.         unit = autonext_unit_inbox(dside, map->curunit, map->vp);
  1196.         if (unit
  1197.             && unit->plan
  1198.             && !unit->plan->asleep
  1199.             && !unit->plan->reserve
  1200.             && !unit->plan->delayed
  1201.             && unit->plan->waitingfortasks
  1202.             ) {
  1203.             map->curunit = unit;
  1204.             select_exactly_one_unit(map, map->curunit);
  1205.             goto blink;
  1206.         }
  1207.         /* Look for the next unit. */
  1208.         unit = find_next_awake_mover(dside, map->curunit);
  1209.         if (unit
  1210.             && unit->plan
  1211.             && !unit->plan->asleep
  1212.             && !unit->plan->reserve
  1213.             && !unit->plan->delayed
  1214.             && unit->plan->waitingfortasks
  1215.             ) {
  1216.             map->curunit = unit;
  1217.             select_exactly_one_unit(map, map->curunit);
  1218.             goto blink;
  1219.         }
  1220.         /* Start over from beginning of list. */
  1221.         unit = find_next_awake_mover(dside, NULL);
  1222.         if (unit
  1223.             && unit->plan
  1224.             && !unit->plan->asleep
  1225.             && !unit->plan->reserve
  1226.             && !unit->plan->delayed
  1227.             && unit->plan->waitingfortasks
  1228.             ) {
  1229.             map->curunit = unit;
  1230.             select_exactly_one_unit(map, map->curunit);
  1231.             goto blink;
  1232.         }
  1233.       blink:
  1234.         if (map->curunit != NULL) {
  1235.             int tick_count;
  1236.  
  1237.             tick_count = TickCount();
  1238.             if (tick_count - last_tick_count >= 10) {
  1239.                 last_tick_count = tick_count;
  1240.                 animation_pattern_state = (animation_pattern_state + 1) % 8;
  1241.                 draw_selection_animation(map, map->curunit);
  1242.             }
  1243.         }
  1244.     }
  1245. }
  1246.  
  1247. /* Used to check for any unread required parameters. Returns true if we
  1248.    missed at least one. */
  1249.  
  1250. Boolean
  1251. missed_any_parameters(AppleEvent *message)
  1252. {
  1253.     OSErr err;
  1254.     DescType ignoredActualType;
  1255.     AEKeyword missedKeyword;
  1256.     Size ignoredActualSize;
  1257.     EventRecord    event;
  1258.  
  1259.     err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeKeyword, &ignoredActualType,
  1260.                             (Ptr) &missedKeyword, sizeof(missedKeyword), &ignoredActualSize);
  1261.     /* No error means that we found some unused parameters. */
  1262.     if (err == noErr) {
  1263.         event.message = *(long *) &ignoredActualType;
  1264.         event.where = *(Point *) &missedKeyword;
  1265.         err = errAEEventNotHandled;
  1266.     }
  1267.     /* errAEDescNotFound means that there are no more parameters.  If we get
  1268.        an error code other than that, flag it. */
  1269.     return (err != errAEDescNotFound);
  1270. }
  1271.  
  1272. static pascal OSErr
  1273. do_ae_open_application(AppleEvent *message, AppleEvent *reply, long refcon)
  1274. {
  1275. #pragma unused (message, refcon)
  1276.     OSErr err;
  1277.  
  1278.     if (splash_dialog() == diSplashQuit) {
  1279.         /* Set the global that lets the whole program exit. */
  1280.         eventloopdone = TRUE;
  1281.     }
  1282.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  1283.     return err;
  1284. }
  1285.  
  1286. /* Called when we receive an AppleEvent with an ID of "kAEOpenDocuments".
  1287.    This routine gets the direct parameter, parses it up into little FSSpecs,
  1288.    and opens the first indicated file.  It also shows the technique to be used in
  1289.    determining if you are doing everything the AppleEvent record is telling
  1290.    you.  Parameters can be divided up into two groups: required and optional.
  1291.    Before executing an event, you must make sure that you've read all the
  1292.    required events.  This is done by making an "any more?" call to the
  1293.    AppleEvent manager. */
  1294.  
  1295. static pascal OSErr
  1296. do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
  1297. {
  1298. #pragma unused (refcon)
  1299.  
  1300.     OSErr err, err2;
  1301.     AEDesc theDesc;
  1302.     FSSpec fsspec;
  1303.     short loop;
  1304.     long numFilesToOpen;
  1305.     AEKeyword ignoredKeyWord;
  1306.     DescType ignoredType;
  1307.     Size ignoredSize;
  1308.  
  1309.     theDesc.dataHandle = nil;
  1310.  
  1311.     err = AEGetParamDesc(message, keyDirectObject, typeAEList, &theDesc);
  1312.     if (err)
  1313.       return err;
  1314.     if (!missed_any_parameters(message)) {
  1315.         /* Got all the parameters we need.  Now, go through the direct object,
  1316.            see what type it is, and parse it up. */
  1317.         err = AECountItems(&theDesc, &numFilesToOpen);
  1318.         if (!err) {
  1319.             /* We have numFilesToOpen that need opening, as either a window
  1320.                or to be printed.  Go to it... */
  1321.             for (loop = 1; ((loop <= numFilesToOpen) && (!err)); ++loop) {
  1322.                 err = AEGetNthPtr(&theDesc, loop, typeFSS, &ignoredKeyWord, &ignoredType,
  1323.                                   (Ptr) &fsspec, sizeof(fsspec), &ignoredSize);
  1324.                 if (err)
  1325.                   break;
  1326.                 if (open_game_from_fsspec(&fsspec))
  1327.                   break;
  1328.             }
  1329.         }
  1330.     }
  1331.     err2 = AEDisposeDesc(&theDesc);
  1332.     err = (err ? err : err2);
  1333.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  1334.     return err;
  1335. }
  1336.  
  1337. static pascal OSErr
  1338. do_ae_print_documents(AppleEvent *message, AppleEvent *reply, long refcon)
  1339. {
  1340.     OSErr err;
  1341.  
  1342.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  1343.     return err;
  1344. }
  1345.  
  1346. static pascal OSErr
  1347. do_ae_quit_application(AppleEvent *message, AppleEvent *reply, long refcon)
  1348. {
  1349.     OSErr err = noErr;
  1350.  
  1351.     /* Set the global that lets the whole program exit. */
  1352.     /* (should end the game reasonably first?) */
  1353.     eventloopdone = TRUE;
  1354.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  1355.     return noErr;
  1356. }
  1357.  
  1358. static pascal OSErr
  1359. do_ae_join_game(AppleEvent *message, AppleEvent *reply, long refcon)
  1360. {
  1361. #pragma unused (message, refcon)
  1362.     OSErr err = noErr;
  1363.  
  1364.     if (playersetupwin != nil) {
  1365.         add_remote_player(NULL);
  1366.     } else {
  1367.         beep();
  1368.         beep();
  1369.         beep();
  1370.     }
  1371.     return err;
  1372. }
  1373.  
  1374. void
  1375. connect_game_dialog()
  1376. {
  1377.     hosting = FALSE;
  1378.     connection_method_dialog();
  1379.     init_connection_method();
  1380.     if (connection_method > 0) {
  1381.         low_send(0, "join");
  1382.     }
  1383. }
  1384.  
  1385. void
  1386. connection_method_dialog()
  1387. {
  1388.     int done = FALSE, newmethod;
  1389.     short ditem;
  1390.     WindowPtr win;
  1391.     PicHandle pic;
  1392.     short itemtype;  Handle itemhandle;  Rect itemrect;
  1393.  
  1394.     newmethod = 9;
  1395.     win = GetNewDialog(170, NULL, (DialogPtr) -1L);
  1396.     ShowWindow(win);
  1397.     SelectWindow(win);
  1398.     while (!done) {
  1399.         ModalDialog(NULL, &ditem);
  1400.         switch (ditem) {
  1401.             case 1:
  1402.                 connection_method = newmethod;
  1403.                 done = TRUE;
  1404.                 break;
  1405.             case 2:
  1406.                 done = TRUE;
  1407.                 break;
  1408.             case 3:
  1409.             case 4:
  1410.             case 5:
  1411.                 break;
  1412.             default:
  1413.                 break;
  1414.         }
  1415.     }
  1416.     DisposDialog(win);
  1417. }
  1418.  
  1419. void init_serial_port(void);
  1420.  
  1421. void
  1422. init_connection_method()
  1423. {
  1424.     switch (connection_method) {
  1425.         case 0:
  1426.             break;
  1427.         case 1:
  1428.             init_serial_port();
  1429.             break;
  1430.         case 2:
  1431.             break;
  1432.         default:
  1433.             break;
  1434.     }
  1435. }
  1436.  
  1437. int ser_input_refnum;
  1438. int ser_output_refnum;
  1439.  
  1440. void
  1441. init_serial_port()
  1442. {
  1443.     OSErr err;
  1444.  
  1445.     if (1 /* using modem port */) {
  1446.         /* Open the modem port. */
  1447.         err = OpenDriver("\p.AOut", (short *) &ser_input_refnum);
  1448.         if (err != 0) {
  1449.             return;
  1450.         }
  1451.         err = OpenDriver("\p.AIn", (short *) &ser_output_refnum);
  1452.         if (err != 0) {
  1453.             CloseDriver(ser_input_refnum);
  1454.             return;
  1455.         }
  1456.     } else {
  1457.         /* Open the printer port. */
  1458.         err = OpenDriver("\p.BOut", (short *) &ser_input_refnum);
  1459.         if (err != 0) {
  1460.             return;
  1461.         }
  1462.         err = OpenDriver("\p.BIn", (short *) &ser_output_refnum);
  1463.         if (err != 0) {
  1464.             CloseDriver(ser_input_refnum);
  1465.             return;
  1466.         }
  1467.     }
  1468. }
  1469.  
  1470. #if 0
  1471.     LocationNameRec foo;
  1472.     PortInfoRec bar;
  1473.     
  1474.     PPCBrowser("\pChoose an Xconq game to join:",
  1475.                "\pXconq", 0, &foo, &bar, NULL, "\p?");
  1476. #endif
  1477.  
  1478. static pascal Boolean
  1479. filter_warning_alert(DialogPtr dialog, EventRecord *evt, short *itemhit)
  1480. {
  1481.     char ch;
  1482.  
  1483.     /* Look for the right kind of event. */
  1484.     switch (evt->what) {
  1485.         case keyDown:
  1486.             ch = evt->message & charCodeMask;
  1487.             if (ch == 3 || ch == 13) {
  1488.                 *itemhit = 1;
  1489.                 return TRUE;
  1490.             }
  1491.             break;
  1492.     }
  1493.     if (evt->modifiers & optionKey)
  1494.       warnings_suppressed = TRUE;
  1495.     return FALSE;
  1496. }
  1497.  
  1498. /* A warning just gets displayed, no other action is taken. */
  1499.  
  1500. void
  1501. low_init_warning(char *str)
  1502. {
  1503.     Str255 buf;
  1504.  
  1505.     /* Cursor may be weird from loading, reset it. */
  1506.     SetCursor(&QD(arrow));
  1507.     c2p(str, buf);
  1508.     ParamText(buf, "\p", "\p", "\p");
  1509.     switch (CautionAlert(aInitWarning, filter_warning_alert_proc)) {
  1510.         case 1:
  1511.             /* Just keep going, player considers warning a false alarm. */
  1512.             break;
  1513.         case 2:
  1514.             /* It would be better to undo everything and blast back to initial choices,
  1515.                but that would be pretty hard to implement, and should be a rare occurrence
  1516.                anyway. */
  1517.             ExitToShell();
  1518.             break;
  1519.     }
  1520. }
  1521.  
  1522. /* An init error is not necessarily fatal, but we still have to start over. */
  1523.  
  1524. void
  1525. low_init_error(char *str)
  1526. {
  1527.     Str255 buf;
  1528.  
  1529.     /* Cursor may be weird from loading, reset it. */
  1530.     SetCursor(&QD(arrow));
  1531.     c2p(str, buf);
  1532.     ParamText(buf, "\p", "\p", "\p");
  1533.     StopAlert(aInitError, nil);
  1534.     /* This is a bad time to choke, no way to recover.  Fortunately,
  1535.        it's not a big loss, since there's no game yet to lose,
  1536.        and so we can just exit directly. */
  1537.     ExitToShell();
  1538. }
  1539.  
  1540. /* Runtime warnings are for when it's important to bug the players,
  1541.    but doesn't necessarily mean imminent danger of a crash. */
  1542.  
  1543. void
  1544. low_run_warning(char *str)
  1545. {
  1546.     Str255 buf;
  1547.  
  1548.     /* If we're not actually in the game yet, make an init warning instead. */
  1549.     if (beforestart) {
  1550.         low_init_warning(str);
  1551.         return;
  1552.     }
  1553.     c2p(str, buf);
  1554.     ParamText(buf, "\p", "\p", "\p");
  1555.     switch (CautionAlert(aRunWarning, filter_warning_alert_proc)) {
  1556.         case 1:
  1557.             /* Just keep going, player considers warning a false alarm. */
  1558.             break;
  1559.         case 2:
  1560.             save_the_game(TRUE, TRUE);
  1561.             ExitToShell();
  1562.             break;
  1563.         case 3:
  1564.             /* Just blast out of here. */
  1565.             ExitToShell();
  1566.             break;
  1567.     }
  1568. }
  1569.  
  1570. /* An run error is fatal, but allow an emergency save, might be able to salvage. */
  1571.  
  1572. void
  1573. low_run_error(char *str)
  1574. {
  1575.     Str255 buf;
  1576.  
  1577.     /* If we're not actually in the game yet, make an init error instead. */
  1578.     if (beforestart) {
  1579.         low_init_error(str);
  1580.         return;
  1581.     }
  1582.     /* Make some space available, in case this is a memory exhaustion error. */
  1583.     if (spare != nil) {
  1584.         DisposHandle(spare);
  1585.         spare = nil;
  1586.     }
  1587.     c2p(str, buf);
  1588.     ParamText(buf, "\p", "\p", "\p");
  1589.     switch (StopAlert(aRunError, nil)) {
  1590.         case 1:
  1591.             break;
  1592.         case 2:
  1593.             save_the_game(TRUE, TRUE);
  1594.             break;
  1595.     }
  1596.     /* We're outta here - just ahead of scrambled heaps and dangling ptrs! */
  1597.     ExitToShell();
  1598. }
  1599.  
  1600. static FILE *pffp;
  1601.  
  1602. static int first_print = TRUE;
  1603.  
  1604. void
  1605. print_form(form)
  1606. Obj *form;
  1607. {
  1608.     if (pffp == NULL) {
  1609.         pffp = fopen("Xconq.PrintOut", (first_print ? "w" : "a"));
  1610.         first_print = FALSE;
  1611.     }
  1612.     print_form_and_value(pffp, form);
  1613.     fflush(pffp);
  1614. }
  1615.  
  1616. void
  1617. end_printing_forms()
  1618. {
  1619.     if (pffp != NULL) {
  1620.         fclose(pffp);
  1621.         pffp = NULL;
  1622.     }
  1623. }
  1624.  
  1625. /* This is true when a side has a display that may be safely written to. */
  1626.  
  1627. int
  1628. active_display(Side *side)
  1629. {
  1630.     return (side && side->ui && side->ui->active);
  1631. }
  1632.  
  1633. /* The Mac never has any display buffers to flush. */
  1634.  
  1635. void
  1636. flush_display_buffers(Side *side)
  1637. {
  1638. }
  1639.  
  1640. /* Detect types of windows. */
  1641.  
  1642. int
  1643. is_da_window(WindowPtr win)
  1644. {
  1645.     return (win != nil && ((WindowPeek) win)->windowKind < 0);
  1646. }
  1647.  
  1648. int
  1649. is_app_window(WindowPtr win)
  1650. {
  1651.     return (win != nil && ((WindowPeek) win)->windowKind >= 0);
  1652. }
  1653.  
  1654. void
  1655. low_notify(Side *side, char *str)
  1656. {
  1657.     if (!active_display(side))
  1658.       return;
  1659.     append_notice(str);
  1660. }
  1661.  
  1662. /* Kernel callback to update info about the given side. */
  1663.  
  1664. void
  1665. update_side_display(Side *side, Side *side2, int rightnow)
  1666. {
  1667.     GrafPtr oldport;
  1668.     extern int gamenumsides;
  1669.  
  1670.     if (active_display(side) && side2 != NULL) {
  1671.         GetPort(&oldport);
  1672.         if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  1673.             if (gamenumsides == numsides) {
  1674.                 SetPort(gamewin);
  1675.                 draw_side_status(side2);
  1676.             } else {
  1677.                 /* A side must have been added recently; redraw
  1678.                    the entire window this time. */
  1679.                 if (eimages[side_number(side2)] == NULL)
  1680.                   init_emblem_images(side2);
  1681.                 draw_game();
  1682.             }
  1683.         }
  1684.         SetPort(oldport);
  1685.         if (side2 == dside && !side->ingame && side->status == 0 && wasingame) {
  1686.             /* (should be able to quit from here?) */
  1687.             CautionAlert(aOutOfGame, nil); 
  1688.             wasingame = FALSE;
  1689.             dside->may_set_see_all = TRUE;
  1690.         }
  1691.     }
  1692. }
  1693.  
  1694. /* Kernel callback to show the current turn. */
  1695.  
  1696. void
  1697. update_turn_display(Side *side, int rightnow)
  1698. {
  1699.     GrafPtr oldport;
  1700.     Map *map;
  1701.     extern char *curseasonname;
  1702.  
  1703.     if (active_display(side)) {
  1704.         strcpy(curdatestr + 1, absolute_date_string(g_turn()));
  1705.         if (curseasonname != NULL) {
  1706.             strcat(curdatestr + 1, " (");
  1707.             strcat(curdatestr + 1, curseasonname);
  1708.             strcat(curdatestr + 1, ")");
  1709.         }
  1710.         curdatestr[0] = strlen(curdatestr + 1);
  1711.         GetPort(&oldport);
  1712.         if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  1713.             SetPort(gamewin);
  1714.             draw_game_date();
  1715.         }
  1716.         for_all_maps(map) {
  1717.             if (map->toplineh > 0) {
  1718.                 SetPort(map->window);
  1719.                 draw_top_line(map);
  1720.             }
  1721.             if (map->topunith > 0) {
  1722.                 SetPort(map->window);
  1723.                 draw_unit_info(map);
  1724.             }
  1725.         }
  1726.         /* This routine might have been called because the game is over. */
  1727.         if (endofgame && !told_outcome && side == dside) {
  1728.             if (side_won(dside)) {
  1729.                 won_game_dialog();
  1730.             } else if (side_lost(dside)) {
  1731.                 lost_game_dialog();
  1732.             } else {
  1733.                 game_over_dialog();
  1734.             }
  1735.             told_outcome = TRUE;
  1736.             side->may_set_see_all = TRUE;
  1737.         }
  1738.         SetPort(oldport);
  1739.     }
  1740. }
  1741.  
  1742. /* Callback that gets run once after all turn setup is done but before any movement. */
  1743.  
  1744. void
  1745. update_action_display(Side *side, int rightnow)
  1746. {
  1747.     GrafPtr oldport;
  1748.     Map *map;
  1749.     List *list;
  1750.     UnitCloseup *unitcloseup;
  1751.  
  1752.     if (active_display(side)) {
  1753.         GetPort(&oldport);
  1754.         for_all_maps(map) {
  1755.             draw_selections(map);
  1756.             if (map->autoselect) {
  1757.                 unselect_all(map);
  1758.                 map->curunit = NULL;
  1759.             }
  1760.         }
  1761.         for_all_lists(list) {
  1762.             reorganize_list(list);
  1763.         }
  1764.         for_all_unit_closeups(unitcloseup) {
  1765.             force_update(unitcloseup->window);
  1766.         }
  1767.         SetPort(oldport);
  1768.     }
  1769. }
  1770.  
  1771. void
  1772. update_action_result_display(Side *side, Unit *unit, int rslt, int rightnow)
  1773. {
  1774.     Action *action;
  1775.  
  1776.     if (active_display(side)) {
  1777.         action = (unit->act ? &(unit->act->nextaction) : NULL);
  1778.         if (action == NULL)
  1779.           return;
  1780.         DGprintf("%s %s result is %s\n",
  1781.                 unit_desig(unit), action_desig(action), hevtdefns[rslt].name);
  1782.         switch (action->type) {
  1783.             case ACTION_CREATE_IN:
  1784.             case ACTION_CREATE_AT:
  1785.             case ACTION_BUILD:
  1786.                  /* If any construction-type action succeeded, we should update
  1787.                     the list of types in the construction window, because the
  1788.                     counts of types might have changed. */
  1789.                 if (rslt == A_ANY_DONE) {
  1790.                     update_construction_type_list();
  1791.                 }
  1792.                 break;
  1793.         }
  1794.         update_unit_in_maps(unit);
  1795.     }
  1796. }
  1797.  
  1798. void
  1799. update_event_display(Side *side, HistEvent *hevt, int rightnow)
  1800. {
  1801.     if (active_display(side)) {
  1802.         /* Tweak the history window if it's up. */
  1803.         if (historywin != nil && ((WindowPeek) historywin)->visible) {
  1804.             update_history_window(hevt);
  1805.         }
  1806.     }
  1807. }
  1808.  
  1809. void
  1810. update_fire_at_display(Side *side, Unit *unit, Unit *unit2, int m, int rightnow)
  1811. {
  1812.     int i, sx1, sy1, sw1, sh1, sx2, sy2, sw2, sh2, dx, dy, xx, yy;
  1813.     int startticks, innerticks;
  1814.     Map *map;
  1815.     GrafPtr oldport, curport = NULL;
  1816.  
  1817.     if (active_display(side)) {
  1818.         GetPort(&oldport);
  1819.         startticks = TickCount();
  1820.         i = 0;
  1821.         /* Tweak the pen modes of all the maps. */
  1822.         for_all_maps(map) {
  1823.             SetPort(map->window);
  1824.             PenMode(patXor);
  1825.             if (map->vp->hw > 10)
  1826.               PenSize(2, 2);
  1827.             else
  1828.               PenSize(1, 1);
  1829.         }
  1830.         while (TickCount() < startticks + 32) {
  1831.             innerticks = TickCount();
  1832.             for_all_maps(map) {
  1833.                 if (curport != map->window) {
  1834.                     SetPort(map->window);
  1835.                     curport = map->window;
  1836.                 }
  1837.                 m_xform_unit_self(map, unit, &sx1, &sy1, &sw1, &sh1);
  1838.                 m_xform_unit_self(map, unit2, &sx2, &sy2, &sw2, &sh2);
  1839.                 compute_fire_line_segment(sx1 + sw1 / 2, sy1 + sh1 / 2,
  1840.                                           sx2 + sw2 / 2, sy2 + sh2 / 2,
  1841.                                           i, 4, &xx, &yy, &dx, &dy);
  1842.                 MoveTo(xx, yy);  Line(dx, dy);
  1843.             }
  1844.             /* 2 here seems a bit slowish */
  1845.             while (TickCount() < innerticks + 1)
  1846.               ;
  1847.             ++i;
  1848.         }
  1849.         /* Restore the pen modes of all the maps. */
  1850.         for_all_maps(map) {
  1851.             SetPort(map->window);
  1852.             PenNormal();
  1853.         }
  1854.         SetPort(oldport);
  1855.     }
  1856. }
  1857.  
  1858. void
  1859. update_fire_into_display(Side *side, Unit *unit, int x2, int y2, int z2, int m, int rightnow)
  1860. {
  1861.     int i, sx1, sy1, sw1, sh1, sx2, sy2, sw2, sh2, dx, dy, xx, yy;
  1862.     int startticks, innerticks;
  1863.     Map *map;
  1864.     GrafPtr oldport, curport = NULL;
  1865.  
  1866.     if (active_display(side)) {
  1867.         GetPort(&oldport);
  1868.         startticks = TickCount();
  1869.         i = 0;
  1870.         /* Tweak the pen modes of all the maps. */
  1871.         for_all_maps(map) {
  1872.             SetPort(map->window);
  1873.             PenMode(patXor);
  1874.             if (map->vp->hw > 10)
  1875.               PenSize(2, 2);
  1876.             else
  1877.               PenSize(1, 1);
  1878.         }
  1879.         while (TickCount() < startticks + 32) {
  1880.             innerticks = TickCount();
  1881.             for_all_maps(map) {
  1882.                 if (curport != map->window) {
  1883.                     SetPort(map->window);
  1884.                     curport = map->window;
  1885.                 }
  1886.                 m_xform_unit_self(map, unit, &sx1, &sy1, &sw1, &sh1);
  1887.                 xform(map, x2, y2, &sx2, &sy2);
  1888.                 compute_fire_line_segment(sx1 + sw1 / 2, sy1 + sh1 / 2,
  1889.                                           sx2 + map->vp->hw / 2, sy2 + map->vp->hh / 2,
  1890.                                           i, 4, &xx, &yy, &dx, &dy);
  1891.                 MoveTo(xx, yy);  Line(dx, dy);
  1892.             }
  1893.             /* 2 here seems a bit slowish */
  1894.             while (TickCount() < innerticks + 1)
  1895.               ;
  1896.             ++i;
  1897.         }
  1898.         /* Restore the pen modes of all the maps. */
  1899.         for_all_maps(map) {
  1900.             SetPort(map->window);
  1901.             PenNormal();
  1902.         }
  1903.         SetPort(oldport);
  1904.     }
  1905. }
  1906.  
  1907. /* Update any displayed info about the given unit. */
  1908.  
  1909. void
  1910. update_unit_display(Side *side, Unit *unit, int rightnow)
  1911. {
  1912.     UnitCloseup *unitcloseup;
  1913.  
  1914.     if (active_display(side) && unit != NULL) {
  1915.         update_unit_in_maps(unit);
  1916.         if (1 /* unit visible to side in any way */ && inside_area(unit->x, unit->y)) {
  1917.             update_cell_display(side, unit->x, unit->y, TRUE);
  1918.         }
  1919.         update_unit_in_lists(unit);
  1920.         if ((unitcloseup = find_unit_closeup(unit)) != NULL
  1921.             && 1 /* window is visible */) {
  1922.             draw_unit_closeup(unitcloseup);
  1923.         }
  1924.         if (unit->side != NULL && unit->act != NULL) {
  1925.             update_side_display(side, unit->side, rightnow);
  1926.         }
  1927.         if (constructionwin != nil
  1928.             && ((WindowPeek) constructionwin)->visible) {
  1929.             update_construction_unit_list(unit);
  1930.         }
  1931.     }
  1932. }
  1933.  
  1934. void
  1935. update_unit_acp_display(Side *side, Unit *unit, int rightnow)
  1936. {
  1937.     UnitCloseup *unitcloseup;
  1938.  
  1939.     if (active_display(side) && unit != NULL) {
  1940.         update_unit_in_maps(unit);
  1941. #if 0  /* maybe add later, maybe not - acp change not usually visible tho */
  1942.         if (1 /* unit visible to side in any way */ && inside_area(unit->x, unit->y)) {
  1943.             update_cell_display(side, unit->x, unit->y, TRUE);
  1944.         }
  1945. #endif
  1946.         update_unit_in_lists(unit);
  1947.         unitcloseup = find_unit_closeup(unit);
  1948.         if (unitcloseup != NULL && (((WindowPeek) (unitcloseup->window))->visible)) {
  1949.             draw_unit_closeup(unitcloseup);
  1950.         }
  1951.     }
  1952. }
  1953.  
  1954. void
  1955. update_unit_in_maps(Unit *unit)
  1956. {
  1957.     Map *map;
  1958.  
  1959.     if (!side_controls_unit(dside, unit) || !alive(unit)) {
  1960.         for_all_maps(map) {
  1961.             unselect_unit_on_map(map, unit);
  1962.             if (unit == map->curunit) {
  1963.                 map->curunit = NULL;
  1964.             }
  1965.         }
  1966.         return;
  1967.     }
  1968.     if (side_controls_unit(dside, unit)) {
  1969.         for_all_maps(map) {
  1970.             if (map->topunith > 0 && map->numselections == 1 && unit == map->selections[0]) {
  1971.                 draw_unit_info(map);
  1972.             }
  1973.         }
  1974.     }
  1975. }
  1976.  
  1977. void
  1978. update_clock_display(Side *side, int rightnow)
  1979. {
  1980.     GrafPtr oldport;
  1981. #if 0
  1982.     Map *map;
  1983. #endif
  1984.     time_t now;
  1985.     extern time_t lastnow;
  1986.  
  1987.     if (active_display(side)) {
  1988.         time(&now);
  1989.         /* If no changes since the last draw, jump out of here. */
  1990.         if (now == lastnow)
  1991.           return;
  1992.         GetPort(&oldport);
  1993.         if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  1994.             SetPort(gamewin);
  1995.             draw_game_clocks();
  1996.         }
  1997. #if 0  /* no clock display in the topline yet */
  1998.         for_all_maps(map) {
  1999.             if (map->toplineh > 0) {
  2000.                 SetPort(map->window);
  2001.                 draw_top_line(map);
  2002.             }
  2003.         }
  2004. #endif
  2005.         SetPort(oldport);
  2006.     }
  2007. }
  2008.  
  2009. void
  2010. update_all_progress_displays(char *str, int s)
  2011. {
  2012.     GrafPtr oldport;
  2013.     extern char *game_progress_str;
  2014.  
  2015.     if (!active_display(dside))
  2016.       return;
  2017.     game_progress_str = str;
  2018.     GetPort(&oldport);
  2019.     if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  2020.         SetPort(gamewin);
  2021.         draw_game_progress();
  2022.     }
  2023.     SetPort(oldport);
  2024. }
  2025.  
  2026. /* Bring up a modal dialog saying that the player has won. */
  2027.  
  2028. void
  2029. won_game_dialog()
  2030. {
  2031.     int done = FALSE;
  2032.     short ditem;
  2033.     WindowPtr win;
  2034.  
  2035.     win = GetNewDialog(dWinGame, NULL, (DialogPtr) -1L);
  2036.     ShowWindow(win);
  2037.     while (!done) {
  2038.         draw_default_button(win, diWinGameQuit);
  2039.         SetCursor(&QD(arrow));
  2040.         ModalDialog(NULL, &ditem);
  2041.         switch (ditem) {
  2042.             case diWinGameQuit:
  2043.                 ExitToShell();
  2044.                 break;
  2045.             case diWinGameContinue:
  2046.                 done = TRUE;
  2047.                 break;
  2048.             default:
  2049.                 break;
  2050.         }
  2051.     }
  2052.     DisposDialog(win);
  2053. }
  2054.  
  2055. /* Bring up a modal dialog saying that the player has lost. */
  2056.  
  2057. void
  2058. lost_game_dialog()
  2059. {
  2060.     int done = FALSE;
  2061.     short ditem;
  2062.     WindowPtr win;
  2063.     extern int forcedtoresign;
  2064.  
  2065.     /* If quitting required a resignation, the player just
  2066.        wants out, with no dwelling on final position, so
  2067.        bypass the dialog here. */
  2068.     if (forcedtoresign) {
  2069.         ExitToShell();
  2070.         return;
  2071.     }
  2072.     win = GetNewDialog(dLoseGame, NULL, (DialogPtr) -1L);
  2073.     ShowWindow(win);
  2074.     while (!done) {
  2075.         draw_default_button(win, diLoseGameQuit);
  2076.         SetCursor(&QD(arrow));
  2077.         ModalDialog(NULL, &ditem);
  2078.         switch (ditem) {
  2079.             case diLoseGameQuit:
  2080.                 ExitToShell();
  2081.                 break;
  2082.             case diLoseGameContinue:
  2083.                 done = TRUE;
  2084.                 break;
  2085.             default:
  2086.                 break;
  2087.         }
  2088.     }
  2089.     DisposDialog(win);
  2090. }
  2091.  
  2092. /* Bring up a modal dialog saying that the game has ended, with no
  2093.    implication of the player having either won or lost. */
  2094.  
  2095. void
  2096. game_over_dialog()
  2097. {
  2098.     int done = FALSE;
  2099.     short ditem;
  2100.     WindowPtr win;
  2101.  
  2102.     win = GetNewDialog(dGameOver, NULL, (DialogPtr) -1L);
  2103.     ShowWindow(win);
  2104.     while (!done) {
  2105.         draw_default_button(win, diGameOverQuit);
  2106.         SetCursor(&QD(arrow));
  2107.         ModalDialog(NULL, &ditem);
  2108.         switch (ditem) {
  2109.             case diGameOverQuit:
  2110.                 ExitToShell();
  2111.                 break;
  2112.             case diGameOverContinue:
  2113.                 done = TRUE;
  2114.                 break;
  2115.             default:
  2116.                 break;
  2117.         }
  2118.     }
  2119.     DisposDialog(win);
  2120. }
  2121.  
  2122. /* Update the displays to reflect the arrival of a message from another
  2123.    side. */
  2124.  
  2125. void
  2126. update_message_display(Side *side, Side *sender, char *str, int rightnow)
  2127. {
  2128.     int done = FALSE;
  2129.     short ditem;
  2130.     Str255 tmpstr;
  2131.     WindowPtr win;
  2132.     short itemtype;  Handle itemhandle;  Rect itemrect;
  2133.  
  2134.     if (active_display(side)) {
  2135.         if (str == NULL)
  2136.           str = "";
  2137.         if (1 /* chose to make a dialog */) {
  2138.             win = GetNewDialog(dMessageReceive, NULL, (DialogPtr) -1L);
  2139.             GetDItem(win, diMessageReceiveText, &itemtype, &itemhandle, &itemrect);
  2140.             c2p(str, tmpstr);
  2141.             SetIText(itemhandle, tmpstr);
  2142.             ShowWindow(win);
  2143.             while (!done) {
  2144.                 draw_default_button(win, diMessageReceiveOK);
  2145.                 SetCursor(&QD(arrow));
  2146.                 ModalDialog(NULL, &ditem);
  2147.                 switch (ditem) {
  2148.                     case diMessageReceiveOK:
  2149.                         done = TRUE;
  2150.                         break;
  2151.                     default:
  2152.                         break;
  2153.                 }
  2154.             }
  2155.             DisposDialog(win);
  2156.         } else {
  2157.             notify(side, "From %s: %s", side_desig(sender), str);
  2158.         }
  2159.     }
  2160. }
  2161.  
  2162. void
  2163. action_point(Side *side, int x, int y)
  2164. {
  2165.     Map *map;
  2166.  
  2167.     if (side != dside)
  2168.       return;
  2169.     if (!inside_area(x, y))
  2170.       return;
  2171.  
  2172.     for_all_maps(map) {
  2173.         if (map->follow_action && !in_middle(map, x, y)) {
  2174.             set_view_focus(map->vp, x, y);
  2175.             m_center_on_focus(map);
  2176.             set_map_scrollbars(map);
  2177.             force_map_update(map);
  2178.         }
  2179.     }    
  2180. }
  2181.  
  2182. /* Support for movie display. */
  2183.  
  2184. int
  2185. schedule_movie(Side *side, enum movie_type movie, ...)
  2186. {
  2187.     int i;
  2188.     va_list ap;
  2189.  
  2190.     if (numscheduled >= 10)
  2191.       return FALSE;
  2192.     if (side != dside)
  2193.       return FALSE;
  2194.     memset(&(movies[numscheduled]), 0, sizeof(struct a_movie));
  2195.     movies[numscheduled].type = movie;
  2196.     va_start(ap, movie);
  2197.     for (i = 0; i < 5; ++i)
  2198.       movies[numscheduled].args[i] = va_arg(ap, int);
  2199.     va_end(ap);
  2200.     ++numscheduled;
  2201.     return TRUE;
  2202. }
  2203.  
  2204. void
  2205. play_movies(SideMask sidemask)
  2206. {
  2207.     int i, j, unitid, startticks, innerticks;
  2208.     Map *map;
  2209.     Unit *unit;
  2210.     GrafPtr oldport, curport = NULL;
  2211.     long startcount;
  2212.  
  2213.     if (!side_in_set(dside, sidemask))
  2214.       return;
  2215.     if (1 /* anything visible */) {
  2216.         GetPort(&oldport);
  2217.         startticks = TickCount();
  2218.         i = 0;
  2219.         /* Tweak the pen modes of all the maps. */
  2220.         for_all_maps(map) {
  2221.             SetPort(map->window);
  2222.             PenMode(patXor);
  2223.             if (map->vp->hw > 10)
  2224.               PenSize(2, 2);
  2225.             else
  2226.               PenSize(1, 1);
  2227.         }
  2228.         while (TickCount() < startticks + 32) {
  2229.             innerticks = TickCount();
  2230.             for (j = 0; j < numscheduled; ++j) {
  2231.                 switch (movies[j].type) {
  2232.                     case movie_null:
  2233.                         break;
  2234.                     case movie_miss:
  2235.                         unitid = movies[j].args[0];
  2236.                         unit = find_unit(unitid);
  2237.                         if (unit == NULL || !in_area(unit->x, unit->y))
  2238.                           continue;
  2239.                         for_all_maps(map) {
  2240.                             if (curport != map->window) {
  2241.                                 SetPort(map->window);
  2242.                                 curport = map->window;
  2243.                             }
  2244.                             draw_unit_blast(map, unit, 0);
  2245.                         }
  2246.                         startcount = TickCount();
  2247.                         play_sound("crunch");
  2248.                         /* Delay for part of a second (should relinquish cpu tho) */
  2249.                         while ((TickCount() - startcount) < 10)
  2250.                           ;
  2251.                         for_all_maps(map) {
  2252.                             if (curport != map->window) {
  2253.                                 SetPort(map->window);
  2254.                                 curport = map->window;
  2255.                             }
  2256.                             clear_unit_blast(map, unit, 0);
  2257.                         }
  2258.                         break;
  2259.                     case movie_hit:
  2260.                         unitid = movies[j].args[0];
  2261.                         unit = find_unit(unitid);
  2262.                         if (unit == NULL || !in_area(unit->x, unit->y))
  2263.                           continue;
  2264.                         for_all_maps(map) {
  2265.                             if (curport != map->window) {
  2266.                                 SetPort(map->window);
  2267.                                 curport = map->window;
  2268.                             }
  2269.                             draw_unit_blast(map, unit, 1);
  2270.                         }
  2271.                         startcount = TickCount();
  2272.                         play_sound("crunch");
  2273.                         play_sound("boom");
  2274.                         /* Delay for part of a second (should relinquish cpu tho) */
  2275.                         while ((TickCount() - startcount) < 10)
  2276.                           ;
  2277.                         for_all_maps(map) {
  2278.                             if (curport != map->window) {
  2279.                                 SetPort(map->window);
  2280.                                 curport = map->window;
  2281.                             }
  2282.                             clear_unit_blast(map, unit, 1);
  2283.                         }
  2284.                         break;
  2285.                     case movie_death:
  2286.                         unitid = movies[j].args[0];
  2287.                         unit = find_unit(unitid);
  2288.                         if (unit == NULL || !in_area(unit->x, unit->y))
  2289.                           continue;
  2290.                         for_all_maps(map) {
  2291.                             if (curport != map->window) {
  2292.                                 SetPort(map->window);
  2293.                                 curport = map->window;
  2294.                             }
  2295.                             draw_unit_blast(map, unit, 2);
  2296.                         }
  2297.                         startcount = TickCount();
  2298.                         play_sound("crunch");
  2299.                         play_sound("boom");
  2300.                         /* Delay for part of a second (should relinquish cpu tho) */
  2301.                         while ((TickCount() - startcount) < 10)
  2302.                           ;
  2303.                         for_all_maps(map) {
  2304.                             if (curport != map->window) {
  2305.                                 SetPort(map->window);
  2306.                                 curport = map->window;
  2307.                             }
  2308.                             clear_unit_blast(map, unit, 2);
  2309.                         }
  2310.                         break;
  2311.                     case movie_nuke:
  2312.                         /* ??? */
  2313.                         break;
  2314.                     case movie_extra_0:
  2315.                         /* Just play the given sound. */
  2316.                         play_sound((char *) movies[j].args[0]);
  2317.                         break;
  2318.                     default:
  2319.                         break;
  2320.                 }
  2321.             }
  2322.             while (TickCount() < innerticks + 32)
  2323.               ;
  2324.             ++i;
  2325.         }
  2326.         /* Restore the pen modes of all the maps. */
  2327.         for_all_maps(map) {
  2328.             SetPort(map->window);
  2329.             PenNormal();
  2330.         }
  2331.         SetPort(oldport);
  2332.     }
  2333.     numscheduled = 0;
  2334. }
  2335.  
  2336. void
  2337. play_sound(char *soundname)
  2338. {
  2339.     Str255 sndnamebuf;
  2340.     Handle sound;
  2341.  
  2342.     if (!playsounds || empty_string(soundname) || numsoundplays >= 5)
  2343.       return;
  2344.     c2p(soundname, sndnamebuf);
  2345.     sound = GetNamedResource('snd ', sndnamebuf);
  2346.     if (sound != nil) {
  2347.         HLock(sound);
  2348.         /* We play the sound synchronously, because the time delay is needed to
  2349.            make sure the graphics are visible. */
  2350.         SndPlay(nil, (SndListHandle) sound, false);
  2351.         HUnlock(sound);
  2352.         ReleaseResource(sound);
  2353.         ++numsoundplays;
  2354.     } else {
  2355.         run_warning("No sound named \"%s\" available!", soundname);
  2356.         /* (should only complain about each sound once) */
  2357.     }
  2358. }
  2359.  
  2360. /* Move the window to a position staggered from the given last position. */
  2361.  
  2362. void
  2363. stagger_window(WindowPtr win, int *lasthp, int *lastvp)
  2364. {
  2365.     int h, v, retry = 0;
  2366.     Rect winrect;
  2367.     GrafPtr oldport;
  2368.  
  2369.     if (*lasthp > 0 && *lastvp > 0) {
  2370.         while (1) {
  2371.             h = *lasthp + 20;  v = *lastvp + 20;
  2372.             /* Let windows go partly off the screen, but keep at least the top
  2373.                40x40 pixels visible. */
  2374.             if (!position_on_screen(h + 40, v + 40)) {
  2375.                 if (retry < 20) {
  2376.                     h = retry * 20; v = 40;
  2377.                     ++retry;
  2378.                 } else {
  2379.                     /* This is getting out of hand - just pick something. */
  2380.                     h = 20;  v = 40;
  2381.                     break;
  2382.                 }
  2383.             } else if (!position_already_used(h, v)) {
  2384.                 break;
  2385.             }
  2386.         }
  2387.         MoveWindow(win, h, v, FALSE);
  2388.         *lasthp = h;  *lastvp = v;
  2389.     } else {
  2390.         /* Don't move the first window, but do record its position. */
  2391.         GetPort(&oldport);
  2392.         SetPort(win);
  2393.         winrect = win->portRect;
  2394.         LocalToGlobal(&top_left(winrect));
  2395.         *lasthp = winrect.left;  *lastvp = winrect.top;
  2396.         SetPort(oldport);
  2397.     }
  2398. }
  2399.  
  2400. /* Return true if the given position is visible on a screen somewhere. */
  2401.  
  2402. int
  2403. position_on_screen(int h, int v)
  2404. {
  2405.     Point pnt;
  2406.     GDHandle screen;
  2407.  
  2408.     pnt.h = h;  pnt.v = v;
  2409.     if (hasColorQD) {    
  2410.         for (screen = GetDeviceList(); screen != nil; screen = GetNextDevice(screen)) {
  2411.             if (TestDeviceAttribute(screen, screenDevice)
  2412.                 && TestDeviceAttribute(screen, screenActive)) {
  2413.                 if (PtInRect(pnt, &((*screen)->gdRect)))
  2414.                   return TRUE;
  2415.             }
  2416.         }
  2417.     } else {
  2418.         if (PtInRect(pnt, &(QD(screenBits).bounds)))
  2419.           return TRUE;
  2420.     }
  2421.     return FALSE;
  2422. }
  2423.  
  2424. /* (should make this more efficient?) */
  2425.  
  2426. int
  2427. position_already_used(int h, int v)
  2428. {
  2429.     int i;
  2430.     Rect winrect;
  2431.     WindowPtr win;
  2432.     GrafPtr oldport;
  2433.     extern int numwindows;
  2434.     extern WindowPtr *winmenuwins;
  2435.  
  2436.     for (i = 0; i < numwindows; ++i) {
  2437.         win = winmenuwins[i];
  2438.         GetPort(&oldport);
  2439.         SetPort(win);
  2440.         winrect = win->portRect;
  2441.         LocalToGlobal(&top_left(winrect));
  2442.         SetPort(oldport);
  2443.         if (h == winrect.left && v == winrect.top)
  2444.           return TRUE;
  2445.     }
  2446.     return FALSE;
  2447. }
  2448.  
  2449. /* (This may only be called if Color Quickdraw is present.) */
  2450.  
  2451. GDHandle
  2452. best_zoom_screen(Rect *rectptr)
  2453. {
  2454.     int greatestarea = 0, sectarea;
  2455.     Rect srect;
  2456.     GDHandle screen = GetDeviceList(), bestscreen = GetMainDevice();
  2457.  
  2458.     while (screen != nil) {
  2459.         if (TestDeviceAttribute(screen, screenDevice)
  2460.             && TestDeviceAttribute(screen, screenActive)) {
  2461.             SectRect(rectptr, &((*screen)->gdRect), &srect);
  2462.             sectarea = (srect.right - srect.left) * (srect.bottom - srect.top);
  2463.             if (sectarea > greatestarea) {
  2464.                 greatestarea = sectarea;
  2465.                 bestscreen = screen;
  2466.             }
  2467.         }
  2468.         screen = GetNextDevice(screen);
  2469.     }
  2470.     return bestscreen;
  2471. }
  2472.  
  2473. void
  2474. set_standard_state(WindowPtr win, int fullw, int fullh)
  2475. {
  2476.     int screenw, screenh, wintitlehgt, mbaradj = 0;
  2477.     Rect winrect, gdrect, zoomrect;
  2478.     GDHandle bestscreen;
  2479.  
  2480.     winrect = win->portRect;
  2481.     LocalToGlobal((Point *) &(winrect.top));
  2482.     LocalToGlobal((Point *) &(winrect.bottom));
  2483.     wintitlehgt = winrect.top - 1 - (*(((WindowPeek) win)->strucRgn))->rgnBBox.top;
  2484.     if (hasColorQD) {
  2485.         /* Get the best screen to zoom on. */
  2486.         bestscreen = best_zoom_screen(&winrect);
  2487.         gdrect = (*bestscreen)->gdRect;
  2488.         /* Adjust to the actual subarea that we can use. */
  2489.         if (bestscreen == GetMainDevice()) {
  2490.             gdrect.top += GetMBarHeight();
  2491.         }
  2492.         InsetRect(&gdrect, 3, 3);
  2493.         gdrect.top += wintitlehgt;
  2494.         screenw = gdrect.right - gdrect.left;  screenh = gdrect.bottom - gdrect.top;
  2495.         if (winrect.left + fullw <= gdrect.right
  2496.             && winrect.top + fullh <= gdrect.bottom) {
  2497.             SetRect(&zoomrect, winrect.left, winrect.top, winrect.left + fullw, winrect.top + fullh);
  2498.         } else if (fullw <= screenw || fullh <= screenh) {
  2499.             SetRect(&zoomrect, gdrect.left, gdrect.top, gdrect.left + fullw, gdrect.top + fullh);
  2500.             if (fullw > screenw)
  2501.               zoomrect.right = gdrect.right;
  2502.             if (fullh > screenh)
  2503.               zoomrect.bottom = gdrect.bottom;
  2504.         } else {
  2505.             zoomrect = gdrect;
  2506.         }
  2507.     } else {
  2508.         zoomrect = QD(screenBits).bounds;
  2509.         zoomrect.top += GetMBarHeight();
  2510.         InsetRect(&zoomrect, 4, 4);
  2511.         zoomrect.top += wintitlehgt;
  2512.     }
  2513.     ((WStateDataPtr) *(((WindowPeek) win)->dataHandle))->stdState = zoomrect;
  2514. }
  2515.  
  2516. void
  2517. get_main_screen_size(int *widp, int *hgtp)
  2518. {
  2519.     Rect rect;
  2520.     GrafPtr mainport;
  2521.     GDHandle mainscreen;
  2522.  
  2523.     if (hasColorQD) {
  2524.         mainscreen = GetMainDevice();
  2525.         rect = (*mainscreen)->gdRect;
  2526.     } else {
  2527.         GetWMgrPort(&mainport);
  2528.         rect = mainport->portRect;
  2529.     }
  2530.     if (widp)
  2531.       *widp = rect.right - rect.left;
  2532.     if (hgtp)
  2533.       *hgtp = rect.bottom - rect.top;
  2534. }
  2535.  
  2536. /* General routine to outline the given item of a given dialog. */
  2537.  
  2538. void
  2539. draw_default_button(DialogPtr dialog, short ditem)
  2540. {
  2541.     GrafPtr oldport;
  2542.     short itemtype;  Handle itemhandle;  Rect itemrect;
  2543.  
  2544.     GetPort(&oldport);
  2545.     SetPort(dialog);
  2546.     GetDItem(dialog, ditem, &itemtype, &itemhandle, &itemrect);
  2547.     PenSize(3, 3);
  2548.     InsetRect(&itemrect, -4, -4);
  2549.     FrameRoundRect(&itemrect, 16, 16);
  2550.     PenNormal();
  2551.     SetPort(oldport);
  2552. }
  2553.  
  2554. char *
  2555. get_string_from_item(Handle itemhandle)
  2556. {
  2557.     char tmpbuf[BUFSIZE];
  2558.     Str255 tmpstr;
  2559.     
  2560.     GetIText(itemhandle, tmpstr);
  2561.     p2c(tmpstr, tmpbuf);
  2562.     return copy_string(tmpbuf);
  2563. }
  2564.  
  2565. /* Cause an update of a window's entire contents. */
  2566.  
  2567. void
  2568. force_update(WindowPtr win)
  2569. {
  2570.     GrafPtr oldport;
  2571.  
  2572.     if (win == nil)
  2573.       return;
  2574.     GetPort(&oldport);
  2575.     SetPort(win);
  2576.     EraseRect(&win->portRect);
  2577.     InvalRect(&win->portRect);
  2578.     SetPort(oldport);
  2579. }
  2580.  
  2581. void
  2582. force_overall_update()
  2583. {
  2584.     Map *map;
  2585.     List *list;
  2586.     UnitCloseup *unitcloseup;
  2587.  
  2588.     force_update(gamewin);
  2589.     force_update(historywin);
  2590.     force_update(constructionwin);
  2591.     force_update(helpwin);
  2592.     force_update(noticewin);
  2593.     force_update(commandwin);
  2594.     force_update(scoreswin);
  2595.     for_all_maps(map) {
  2596.         force_update(map->window);
  2597.     }
  2598.     for_all_lists(list) {
  2599.         force_update(list->window);
  2600.     }
  2601.     for_all_unit_closeups(unitcloseup) {
  2602.         force_update(unitcloseup->window);
  2603.     }
  2604. }
  2605.  
  2606. void
  2607. beep()
  2608. {
  2609.     SysBeep(20);
  2610. }
  2611.  
  2612. void
  2613. update_everything()
  2614. {
  2615.     if (active_display(dside)) {
  2616.         force_overall_update();
  2617.     }
  2618. }
  2619.  
  2620. /* Set the type and creator of the file to be what is expected
  2621.    for a game design. */
  2622.  
  2623. void
  2624. set_game_file_type(char *name)
  2625. {
  2626.     FileParam pb;
  2627.     Str255 tmpstr;
  2628.     
  2629.     c2p(name, tmpstr);
  2630.     pb.ioNamePtr = tmpstr;
  2631.     pb.ioVRefNum = 0;
  2632.     pb.ioFVersNum = 0;
  2633.     pb.ioFDirIndex = 0;
  2634.     if (PBGetFInfoSync((ParmBlkPtr) &pb) == noErr) {
  2635.         pb.ioFlFndrInfo.fdType = 'TEXT';
  2636.         pb.ioFlFndrInfo.fdCreator = XconqSignature;
  2637.         PBSetFInfoSync((ParmBlkPtr) &pb);
  2638.     }
  2639. }
  2640.  
  2641. /* Low-level transmission to another program. */
  2642.  
  2643. void
  2644. low_send(int id, char *buf)
  2645. {
  2646.     Dprintf("Sent: %d \"%s\"\n", id, (buf ? buf : "(null)"));
  2647.     switch (connection_method) {
  2648.         case 0:
  2649.             break;
  2650.         case 1:
  2651.             break;
  2652.         case 9:
  2653.             break;
  2654.         default:
  2655.             break;
  2656.     }
  2657. }
  2658.  
  2659. int
  2660. low_receive(int *id, char *buf, int maxchars, int timeout)
  2661. {
  2662.     int rslt = FALSE;
  2663.  
  2664.     switch (connection_method) {
  2665.         case 0:
  2666.             break;
  2667.         case 1:
  2668.             break;
  2669.         case 9:
  2670.             *id = 2;
  2671.             if (maxchars > 0 && buf != NULL) {
  2672.                 strcpy(buf, "OK");
  2673.             }
  2674.             rslt = TRUE;
  2675.             break;
  2676.         default:
  2677.             break;
  2678.     }
  2679.     if (rslt)
  2680.       Dprintf("Rcvd: %d \"%s\"\n", *id, (buf ? buf : "(null)"));
  2681.     return rslt;
  2682. }
  2683.  
  2684. #ifdef __MWERKS__
  2685.  
  2686. /* Empty definitions for Metrowerks' SIOUX console library. */
  2687.  
  2688. #ifndef __CONSOLE__
  2689. #include <console.h>
  2690. #endif
  2691.  
  2692. short
  2693. InstallConsole(short fd)
  2694. {
  2695. #pragma unused (fd)
  2696.     return 0;
  2697. }
  2698.  
  2699. void
  2700. RemoveConsole(void)
  2701. {
  2702. }
  2703.  
  2704. long
  2705. WriteCharsToConsole(char *buf, long n)
  2706. {
  2707. #pragma unused (buf, n)
  2708.     return 0;
  2709. }
  2710.  
  2711. long ReadCharsFromConsole(char *buf, long n)
  2712. {
  2713. #pragma unused (buf, n)
  2714.     return 0;
  2715. }
  2716.  
  2717. extern char *
  2718. __ttyname(long fd)
  2719. {
  2720.     static char *__devicename = "null device";
  2721.  
  2722.     if (fd >= 0 && fd <= 2)
  2723.       return (__devicename);
  2724.     return NULL;
  2725. }
  2726.  
  2727. #endif /* __MWERKS__ */
  2728.